package com.ayz.gateway.client;

import cn.hutool.log.Log;

import com.ayz.gateway.client.connection.Connection;
import com.ayz.gateway.client.exception.ConnectToServerFailed;
import com.ayz.gateway.client.executor.RequestExecutorRegistry;
import com.ayz.gateway.client.executor.defaults.DefaultRequestExecutorRegistry;
import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ClassName RpcClient
 * @Description TODO: RPC通信服务的客户端
 * @Author 快乐的星球
 * @Date 2023/5/20 23:01
 * @Version 1.0
 **/
@Data
public abstract class RpcClient {

    private final Log LOG=Log.get(RpcClient.class);
    /**
     * 请求执行器注册器
     */
    private final RequestExecutorRegistry requestExecutorRegistry=new DefaultRequestExecutorRegistry();
    /**
     * 存储当前连接
     */
    private Connection currentConnection;
    /**
     * 对于一个 服务来说 如果有多个网关注册中心
     * 那么它应该负载均衡选择一个服务端建立起连接
     * 这可供选择的多个服务端被 ServerListSwitcher 管理
     */
    private ServerListSwitcher serverListSwitcher;
    /**
     * 服务端的地址列表
     */
    private List<String> serverAddressList;
    /**
     * RPC客户端的配置参数
     */
    private RpcClientConfig rpcClientConfig;


    public RpcClient(List<String> serverListAddress, RpcClientConfig rpcClientConfig) {
        this.serverAddressList = serverListAddress;
        this.rpcClientConfig = rpcClientConfig;
        this.serverListSwitcher=new DefaultServerListSwitcher(serverAddressList);
    }

    public RpcClient(RpcClientConfig rpcClientConfig) {
        this.rpcClientConfig = rpcClientConfig;
        this.serverAddressList =new ArrayList<>();
        this.serverListSwitcher=new DefaultServerListSwitcher(serverAddressList);
    }

    public void addServerAddress(String serverAddress){
        this.serverAddressList.add(serverAddress);
    }
    public void addServerAddressList(List<String> serverAddressList){
        this.serverAddressList.addAll(serverAddressList);
    }

    /**
     * 客户端启动
     * TODO: 与服务器建立长连接
     */
    public void start()throws ConnectToServerFailed {
        //1:TODO 与服务端建立长连接
        Connection connectToServer=null;
        int retryTimes = this.rpcClientConfig.getRetryTimes();
        String serverAddress=null;
        while(retryTimes>0 && connectToServer==null){
            retryTimes--;
            serverAddress = this.serverListSwitcher.nextServer();
            connectToServer=connectToServer(serverAddress);
        }

        if(connectToServer==null){
            //启动失败,无法连接到服务器
            throw new ConnectToServerFailed("客户端启动失败,无法根据服务器地址列表与服务器连接连接;服务器列表为:{"+ Arrays.toString(serverAddressList.toArray())+"};最大重试次数为:{"+getRpcClientConfig().getRetryTimes()+"}");
        }
        LOG.info("RpcClient启动成功;连接的服务端的地址为:{"+serverAddress+"}");
        setCurrentConnection(connectToServer);
    }

    /**
     * 与服务端建立起连接
     * @param serverAddress
     * @return
     */
    public abstract Connection connectToServer(String serverAddress);

    /**
     * 在start()方法调用前需要调用当前方法
     * 完成请求执行器注册器的初始化工作
     * @param registryCallback
     */
    public abstract void registryRequestExecutors(RequestExecutorRegistryCallback registryCallback);

    /**
     * RPC客户端的关闭
     * @throws Exception
     */
    public void close() throws Exception{
        if(this.currentConnection!=null){
            this.currentConnection.close();
        }
    }
}
